#include <resource/serialiser.h>
#include <resource/metaclass.h>
#include <util/factory.h>
#include <system/istream.h>
#include <util/rtti.h>

namespace gecko
{

	//---------------------------------------------------------------------------------------------

	Serialiser::Serialiser()
	{

	}

	//---------------------------------------------------------------------------------------------

	Serialiser::~Serialiser()
	{

	}

	//---------------------------------------------------------------------------------------------

	MetaClass* Serialiser::FindMetaClass(MetaClassSet& metaClasses, char* className)
	{
		for (MetaClassSet::iterator itr = metaClasses.begin(); itr != metaClasses.end(); ++itr)
		{
			if (strcmp((*itr)->GetName(), className) == 0)
			{
				return (*itr);
			}
		}

		return NULL;
	}

	//---------------------------------------------------------------------------------------------

	Serialiser::Error Serialiser::SerialiseObjects( IStream& stream, SerialisableList& objectList )
	{
		if (stream.GetMode() == IStream::ModeWrite)
		{
			MetaClassSet metaClasses;

			// collect list of unique meta-classes from list of objects
			for (SerialisableList::Iterator itr = objectList.Begin(); itr != objectList.End(); ++itr)
			{
				if (!(*itr)->Type().IsDerivedFrom(ISerialisable::TYPE()))
				{
					Warning("Class %s is not derived from ISerialisable.", (*itr)->GetMetaClass().GetName());
					return Error_InvalidObject;
				}

				metaClasses.insert(&(*itr)->GetMetaClass());
			}

			// write number of meta-classes
			int numMetaClasses = (int)metaClasses.size();
			stream.Serialise(numMetaClasses);

			// for each meta-class
			for (MetaClassSet::iterator itr = metaClasses.begin(); itr != metaClasses.end(); ++itr)
			{
				// serialise
				(*itr)->SerialiseMetaData(stream);
			}

			// write out number of objects
			int numObjects = (int)objectList.Size();
			stream.Serialise(numObjects);

			// for each object
			for (SerialisableList::Iterator itr = objectList.Begin(); itr != objectList.End(); ++itr)
			{
				// write out class name
				stream.SerialiseString((*itr)->GetMetaClass().GetName());

				// serialise object
				(*itr)->Serialise(stream);
			}
		}
		else
		{
			// read in number of meta-classes
			int numMetaClasses;
			stream.Serialise(numMetaClasses);

			// read in each meta-class into list
			MetaClassSet metaClasses;
			for (int i = 0; i < numMetaClasses; i++)
			{
				MetaClass* metaClass = new MetaClass;

				// serialise
				metaClass->SerialiseMetaData(stream);
				metaClasses.insert(metaClass);
			}

			int numObjects;
			stream.Serialise(numObjects);

			for (int i = 0; i < numObjects; i++)
			{
				char className[gecko::MetaClass::MAX_NAME_LEN];
				stream.SerialiseString(className);

				StrongPtr<IObject> newObject = gecko::Factory<IObject>::Get().Create(className);

				if (!newObject->Type().IsDerivedFrom(ISerialisable::TYPE()))
				{
					Warning("Class %s is not derived from ISerialisable.", className);
					return Error_InvalidObject;
				}

				// find metaclass
				MetaClass* fileMetaClass = FindMetaClass(metaClasses, className);

				// serialise object
				((StrongPtr<ISerialisable>)newObject)->Serialise(stream, fileMetaClass);

				objectList.PushBack(newObject);
			}

			for (MetaClassSet::iterator itr = metaClasses.begin(); itr != metaClasses.end(); ++itr)
			{
				delete (*itr);
			}
		}

		return Error_Success;
	}

	//---------------------------------------------------------------------------------------------

}